﻿using System.Collections.Generic;
using System.Text;

// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

namespace agtest
{
	/// <summary>
	/// FieldListBuilder is a simple helper class used to generate TSQL for a set of SQL Server fields.
	/// Given an input list of fields you can project a field list, a field list with types,
	/// a parameter list and parameter list with types.  Simplifies TSQL generation for
	/// tables and stored procedures given a certain set of fields.
	/// 
	/// Examples:
	/// 
	/// FieldListBuilder fb = new FieldListBuilder("id int, name varchar(255)");
	/// fb.FieldList => "id, name" => "insert into t1 (" + fb.FieldList + ") values (" + fb.ParameterList + ")"
	/// fb.FieldListWithType => "id int, name varchar(255)" => "create table t1 (" + fb.FieldListWithType + ")"
	/// fb.ParameterList => "@id, @name"
	/// fb.ParameterListWithType => "@id int, @name varchar(255)" => "create procedure t(" + fb.ParameterListWithType + ")"
	/// </summary>
	class FieldListBuilder
	{
		/// <summary>
		/// Returns field list in format "fieldName,..."
		/// </summary>
		public string FieldList
		{
			get
			{
				return GenerateList(false, false);
			}
		}

		/// <summary>
		/// Returns field list in format "fieldName fieldType,..."
		/// </summary>
		public string FieldListWithType
		{
			get
			{
				return GenerateList(false, true);
			}
		}

		/// <summary>
		/// Returns field list in format "@fieldName,..."
		/// </summary>
		public string ParameterList
		{
			get
			{
				return GenerateList(true, false);
			}
		}

		/// <summary>
		/// Returns parameter list in format "@fieldName fieldType,..."
		/// </summary>
		public string ParameterListWithType
		{
			get
			{
				return GenerateList(true, true);
			}
		}

		/// <summary>
		/// Generates list with specified options.
		/// </summary>
		/// <param name="useParamHeader">Add the @ parameter header prior to field name</param>
		/// <param name="useType">Add the field type after field name</param>
		/// <returns></returns>
		private string GenerateList(bool useParamHeader, bool useType)
		{
			StringBuilder sb = new StringBuilder(optimalStringBuilderLength);
			foreach (FieldInfo fi in fieldInfo)
			{
				if (useParamHeader)
				{
					sb.Append('@');
				}
				sb.Append(fi.FieldName);
				if (useType)
				{
					sb.Append(' ');
					sb.Append(fi.FieldType);
				}
				sb.Append(',');
			}
			if (sb.Length > 0)
			{
				sb.Length = sb.Length - 1;
			}
			return sb.ToString();
		}

		/// <summary>
		/// List of fields and field types.
		/// </summary>
		private List<FieldInfo> fieldInfo;

		/// <summary>
		/// Optimal string builder length for producing lists.
		/// </summary>
		private int optimalStringBuilderLength;

		/// <summary>
		/// Constructor to build field list.
		/// fieldListString is expected in format "fieldName fieldType,...", for example
		///   => "field1 varchar(255),field2 int, field3 datetime2"
		/// </summary>
		/// <param name="fieldListString"></param>
		public FieldListBuilder(string fieldListString)
		{
			string[] fields = fieldListString.Split(',');
			fieldInfo = new List<FieldInfo>();
			optimalStringBuilderLength = 0;
			foreach (string f in fields)
			{
				optimalStringBuilderLength += (f.Length + 2);
				fieldInfo.Add(new FieldInfo(f));
			}
		}

		/// <summary>
		/// Structure to store field name and type.
		/// </summary>
		private struct FieldInfo
		{
			public string FieldName;
			public string FieldType;
			public FieldInfo(string fieldNameType)
			{
				string[] ft = fieldNameType.Split(' ');
				FieldName = ft[0];
				FieldType = ft[1];
			}
		}
	}
}
